#include "serverEngine.h"
#include "srNetwork.h" // ENUMS


serverEngine::serverEngine() {

    runtimeFps = 0;
    runtimeFpsSmooth = 0;
    runtimeCount = 0;

    memLastKey = 0;

    flagDestroy = 0;
    flagChat = 0;


    mouseX = 0;
    mouseY = 0;
    mouseZ = 0;
    memMouseX = 0;
    memMouseY = 0;
    mouseButton = 0;
    flagMausKlick = 0;
    memMouseDownX = 0;
    memMouseDownY = 0;

    timerFlag100   = 0;
    timerFlag1000  = 0;

    starEngine = new starSystem;
    msg = new msgManager;
    net = new networkManager;
    win = new windowManager;
    gui = new guiManager;
    config = new configManager;

}






serverEngine::~serverEngine() {
    delete starEngine;
    delete msg;
    delete net;
    delete win;
    delete gui;
    delete config;

}





void serverEngine::init(string pPath) {

    // set datacore
    config->Load(pPath);
    config->version = 1;


}





void serverEngine::allegroSetMode(int x, int y, string name) {



    // clean up settings
    allegro_gl_unset_allegro_mode();
    allegro_gl_clear_settings();


    // set windowMode
	set_window_title(name.c_str()); // Title


    // set grafic(GL)
    allegro_gl_set(AGL_DOUBLEBUFFER, 1);
    if(config->gameFullscreen) allegro_gl_set ( AGL_FULLSCREEN, TRUE );
	else allegro_gl_set ( AGL_WINDOWED, TRUE );
    allegro_gl_set(AGL_COLOR_DEPTH, 16);
    allegro_gl_set(AGL_SUGGEST, AGL_DOUBLEBUFFER | AGL_COLOR_DEPTH);
    if(set_gfx_mode(GFX_OPENGL, x, y, 0, 0)) {
        cout << "set_gfx_mode: Could not set grafic mode (" << x << "x" << y << "), Error: " << allegro_error;
	    exit(2);
    }



	set_color_conversion(COLORCONV_24_TO_16); //COLORCONV_KEEP_ALPHA
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);



    // set the OpenGL viewport:
	glViewport( 0, 0, SCREEN_W, SCREEN_H );


    // set to allegro native support mode
    allegro_gl_set_allegro_mode();




}





void serverEngine::allegroInit(int x, int y, string name) {


    //**** Allegro

    // initialize
    if (allegro_init() != 0) {
        cout << "allegro_init: Could not init" << endl;
        exit(2);
    }
    if (install_allegro_gl() != 0) {
        cout << "install_allegro_gl: Could not init" << endl;
        exit(2);
    }
    if (install_keyboard() != 0) {
        cout << "install_keyboard: Could not init" << endl;
        exit(2);
    }
    if (install_timer() != 0) {
        cout << "install_timer: Could not init" << endl;
        exit(2);
    }
    if (install_mouse() == 0) { // 0 = no button
        cout << "install_mouse: Could not init" << endl;
        exit(2);
    }




    // mouse
    enable_hardware_cursor();
    //select_mouse_cursor(MOUSE_CURSOR_ARROW);



    // set allegro sting type
    set_uformat(U_UTF8);






    // set Grafic Mode
    allegroSetMode(x,y,name);







    // timer callbacks
    LOCK_FUNCTION(serverEngine::timerCallback100);
    LOCK_FUNCTION(serverEngine::timerCallback1000);
    install_param_int(serverEngine::timerCallback100,  this,  100); //  1/10 Sekunde
    install_param_int(serverEngine::timerCallback1000, this, 1000); // volle Sekunde





    // mouse cursor (videoMem)
    BITMAP *tmp;
    tmp = load_bitmap("GFX/cursor.bmp", NULL);
    cursor = create_video_bitmap(tmp->w, tmp->h);
    blit(tmp, cursor, 0, 0, 0, 0, tmp->w, tmp->h);
    destroy_bitmap(tmp);



}





void serverEngine::start(bool debuging) {


    flagDebug = debuging;

    allegroInit(config->gameWidth, config->gameHeight, config->gameName);




    //**** debugging (0=nothing, 1=system, 2=runtime)
    net->debug = 2;
    msg->debug = 2;
    gui->debug = 2;
    win->debug = 2;



    //**** init
    msg->Init(); // must be first
    net->Init();
    win->Init();
    gui->Init();
    starEngine->Init(10);



    //**** data pipeing (msg first!)
    gui->IntroduceMessage(msg);
    win->IntroduceMessage(msg);
    net->IntroduceMessage(msg);

    gui->IntroduceWindows(win);
    net->IntroduceWindows(win);

    net->IntroduceGui(gui);

    win->IntroduceNetwork(net);



    //**** pre-render all windows
    win->Render(1);



}


void serverEngine::stop(void) {

    // clean up
    destroy_bitmap(cursor);
    allegro_gl_unset_allegro_mode();
    remove_allegro_gl();

    //allegro_exit(); //TODO: cause segFault

}



bool serverEngine::inputKey(int pKey) {

    memLastKey = (pKey >> 8);
    if((pKey >> 8) == KEY_ESC) { // END chat or EXIT
        if(flagChat) {
            flagChat=0;
            gui->flagTypeChat=0;
        } else flagDestroy = 1;
    }
    else if((pKey >> 8) == KEY_ENTER) { // CHAT
        if(flagChat) {
            flagChat=0;
            gui->flagTypeChat=0;
            net->sendMessage(5);
        } else {
            if(net->getStatus() >= 3) {
                flagChat=1;
                gui->flagTypeChat=1;
                win->windowSetFocus(0);
            }
        }
    }
    else if((pKey >> 8) == KEY_SPACE) {
        //return false;
    }


    // Parse as soon a key is pressed
    if(!flagChat) win->InjectKeys(pKey);  // hand over ascii code
    if(flagChat) gui->InjectKeys(pKey);  // hand over ascii code


    return true;
}


void serverEngine::inputMouse(int pMouseButton, int pMouseX, int pMouseY, int pMouseZ) {


    // Aktuelle position
    mouseX = pMouseX;
    mouseY = pMouseY;
    mouseZ = pMouseZ;

    mouseButton = pMouseButton;


    if(mouseButton & 1) {

        flagMausKlick = 1;

        // start of DownClick
        if(memMouseX == 0) memMouseX = mouseX;
        if(memMouseY == 0) memMouseY = mouseY;

        // Difference
        memMouseDownX = mouseX - memMouseX;
        memMouseDownY = mouseY - memMouseY;

        if((memMouseDownX >= 5 || memMouseDownX <= -5 || memMouseDownY >= 5 || memMouseDownY <= -5) && flagMausMove == 0) {
            flagMausMove = 1; // If at least move the Click difference make official MOVE
        }


        if(flagMausMove) win->windowMove(memMouseDownX, memMouseDownY, memMouseX, memMouseY);

    }
    else if(flagMausKlick) {

        // There was a short move (Click)
        if(memMouseDownX < 5 && memMouseDownX > -5 && memMouseDownY < 5 && memMouseDownY > -5) {

            // If Click is not already chached by window
            if(!win->windowClick(memMouseX, memMouseY)){

                // If click on EXIT
                if(gui->InjectClick(memMouseX, memMouseY)) flagDestroy = 1;

            }

        }
        memMouseDownX = 0;
        memMouseDownY = 0;
        memMouseX = 0;
        memMouseY = 0;
        flagMausMove = 0;
        flagMausKlick= 0;
        win->windowClickRelease();
    }
    /*
    if(mouse_z != MausZbuffer) {
        // Wenn nicht in einem Fenster Gescroolt wurde bitte Zoomen
        if(!Game.winScrolling(mouse_x, mouse_y, MausZbuffer-mouse_z)) {
            if(Zoom < 5 && (MausZbuffer-mouse_z) < 0) Zoom ++;
            else if(Zoom > 1 && (MausZbuffer-mouse_z) > 0) Zoom --;
            Game.mainZoom(Zoom);
        }
        MausZbuffer = mouse_z;
    }
    */



    gui->InjectMouse(pMouseX, pMouseY);
    win->InjectMouse(pMouseX, pMouseY);

}


void serverEngine::timerCallback100(void *arg) {
     serverEngine *_this = (serverEngine*)arg;
     _this->timerFlag100=1;
}



void serverEngine::timerCallback1000(void *arg) {
     serverEngine *_this = (serverEngine*)arg;
     _this->timerFlag1000=1;
}



void serverEngine::timerTick(void) {

    runtimeFps++;
    starEngine->Calculate(1);
    win->Calculate();
    net->Tick();

}



void serverEngine::timerTick100(void) {
    //
}



void serverEngine::timerTick1000(void) {

    //**** timer 1000 stuff
    runtimeFpsSmooth = runtimeFps;
    runtimeFps = 0;
    runtimeCount++;

    // Status Senden
    memLastKey = 0;
    net->TickSecond();
    msg->Tick();

}



bool serverEngine::run(void) {

    while(flagDestroy==0) {


        //**** Input Handling
        poll_mouse();
        inputMouse(mouse_b, mouse_x, mouse_y, mouse_z);
        while (keypressed()) if(!inputKey(readkey())) return false; // restart app



        //***** processing *****
        timerTick();            // every frame (relative)
        if(timerFlag100==1) {   // every tenth second
            timerFlag100 = 0;
            timerTick100();

        }
        if(timerFlag1000==1) {  // every second
            timerFlag1000 = 0;
            timerTick1000();

        }





        //***** Drawing *****
        allegroDraw();



        //***** Rest *****
        rest(10); // Should be 1

    }
    return true;

}



void serverEngine::allegroDraw(void) {


    //**** Clear
    clear_bitmap(screen);



    starEngine->Draw();
    msg->Draw();
    win->Draw();
    gui->Draw();


    // +++++ DEBUG +++++
    textprintf_ex(screen, font, 50, 10, makecol(255, 255, 255), -1, "Client v0.1");
    textprintf_ex(screen, font, 50, 30, makecol(150, 150, 150), -1, "Laufzeit%d", (int)runtimeCount);

    textprintf_ex(screen, font, 50, 40, makecol(150, 150, 150), -1, "Maus(%i,%i) Rad: %i, Mem(%i,%i), Move(%i,%i)", mouseX, mouseY, mouseZ, memMouseX, memMouseY, memMouseDownX, memMouseDownY);
    if(mouseButton & 1) textprintf_ex(screen, font, 50, 50, makecol(150, 150, 150), -1, "MausTasteLinks: JA");
    else textprintf_ex(screen, font, 50, 50, makecol(150, 150, 150), -1, "MausTasteLinks: NEIN");
    if(mouseButton & 2) textprintf_ex(screen, font, 50, 60, makecol(150, 150, 150), -1, "MausTasteRechts: JA");
    else textprintf_ex(screen, font, 50, 60, makecol(150, 150, 150), -1, "MausTasteRechts: NEIN");
    if(mouseButton & 4) textprintf_ex(screen, font, 50, 70, makecol(150, 150, 150), -1, "MausTasteMitte: JA");
    else textprintf_ex(screen, font, 50, 70, makecol(150, 150, 150), -1, "MausTasteMitte: NEIN");
    textprintf_ex(screen, font, 50, 80, makecol(150, 150, 150), -1, "FPS: %i", runtimeFpsSmooth);

    textprintf_ex(screen, font, 50, 120, makecol(150, 150, 150), -1, "Fenster: %i", win->windowGetNumber() );
    textprintf_ex(screen, font, 50, 130, makecol(150, 150, 150), -1, "Focused: %i", win->windowGetFocused() );

    //textprintf_ex(screen, font, 50, 150, makecol(150, 150, 150), -1, "CPU: %s", cpu_vendor );



    //**** Clear & FLIP
    masked_blit(cursor, screen, 0, 0, mouse_x, mouse_y, cursor->w, cursor->h);
    allegro_gl_flip();


}





